/************************************************************************************

Filename    :   OVR_Std.cpp
Content     :   Standard C function implementation
Created     :   September 19, 2012
Notes       :

Copyright   :   Copyright 2014-2016 Oculus VR, LLC All Rights reserved.

Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License");
you may not use the Oculus VR Rift SDK except in compliance with the License,
which is provided at the time of installation or download, or which
otherwise accompanies this software in either electronic or hard copy form.

You may obtain a copy of the License at

http://www.oculusvr.com/licenses/LICENSE-3.3

Unless required by applicable law or agreed to in writing, the Oculus VR SDK
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

************************************************************************************/

#include "OVR_Std.h"
#include "OVR_Alg.h"

// localeconv() call in OVR_strtod()
#include <locale.h>

namespace OVR {

// Source for functions not available on all platforms is included here.

const char* OVR_CDECL OVR_strrchr(const char* pString, int c) {
  const char* pFound = nullptr;

  for (char cCurrent; cCurrent = *pString, cCurrent != '\0'; ++pString) {
    if (cCurrent == c)
      pFound = pString;
  }

  if (pFound)
    return pFound;

  if (c == '\0')
    return pString;

  return nullptr;
}

char* OVR_CDECL OVR_stristr(const char* s1, const char* s2) {
  const char* cp = s1;

  if (!*s2)
    return (char*)s1;

  while (*cp) {
    const char* s = cp;
    const char* t = s2;

    while (*s && *t && (tolower((uint8_t)*s) == tolower((uint8_t)*t)))
      ++s, ++t;

    if (*t == 0)
      return const_cast<char*>(cp);
    ++cp;
  }

  return 0;
}

size_t OVR_CDECL OVR_strlcpy(char* dest, const char* src, size_t destsize) {
  const char* s = src;
  size_t n = destsize;

  if (n && --n) {
    do {
      if ((*dest++ = *s++) == 0)
        break;
    } while (--n);
  }

  if (!n) {
    if (destsize)
      *dest = 0;
    while (*s++) {
    }
  }

  return (size_t)((s - src) - 1);
}

size_t OVR_CDECL OVR_strlcpy(wchar_t* dest, const wchar_t* src, size_t destsize) {
  const wchar_t* s = src;
  size_t n = destsize;

  if (n && --n) {
    do {
      if ((*dest++ = *s++) == 0)
        break;
    } while (--n);
  }

  if (!n) {
    if (destsize)
      *dest = 0;
    while (*s++) {
    }
  }

  return (size_t)((s - src) - 1);
}

size_t OVR_CDECL OVR_strlcat(char* dest, const char* src, size_t destsize) {
  const size_t d = destsize ? OVR_strlen(dest) : 0;
  const size_t s = OVR_strlen(src);
  const size_t t = s + d;

  OVR_ASSERT((destsize == 0) || (d < destsize));

  if (t < destsize)
    memcpy(dest + d, src, (s + 1) * sizeof(*src));
  else {
    if (destsize) {
      memcpy(dest + d, src, ((destsize - d) - 1) * sizeof(*src));
      dest[destsize - 1] = 0;
    }
  }

  return t;
}

size_t OVR_CDECL OVR_strlcat(wchar_t* dest, const wchar_t* src, size_t destsize) {
  const size_t d = destsize ? OVR_strlen(dest) : 0;
  const size_t s = OVR_strlen(src);
  const size_t t = s + d;

  OVR_ASSERT((destsize == 0) || (d < destsize));

  if (t < destsize)
    memcpy(dest + d, src, (s + 1) * sizeof(*src));
  else {
    if (destsize) {
      memcpy(dest + d, src, ((destsize - d) - 1) * sizeof(*src));
      dest[destsize - 1] = 0;
    }
  }

  return t;
}

// Case insensitive compare implemented in platform-specific way.
int OVR_CDECL OVR_stricmp(const char* a, const char* b) {
#if defined(OVR_OS_MS)
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
  return ::_stricmp(a, b);
#else
  return ::stricmp(a, b);
#endif

#else
  return strcasecmp(a, b);
#endif
}

int OVR_CDECL OVR_strnicmp(const char* a, const char* b, size_t count) {
#if defined(OVR_OS_MS)
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
  return ::_strnicmp(a, b, count);
#else
  return ::strnicmp(a, b, count);
#endif

#else
  return strncasecmp(a, b, count);
#endif
}

wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, size_t destsize, const wchar_t* src) {
#if defined(OVR_MSVC_SAFESTRING)
  wcscpy_s(dest, destsize, src);
  return dest;
#elif defined(OVR_OS_MS)
  OVR_UNUSED(destsize);
  wcscpy(dest, src);
  return dest;
#else
  size_t l = OVR_wcslen(src) + 1; // incl term null
  l = (l < destsize) ? l : destsize;
  memcpy(dest, src, l * sizeof(wchar_t));
  return dest;
#endif
}

wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, size_t destsize, const wchar_t* src, size_t count) {
#if defined(OVR_MSVC_SAFESTRING)
  wcsncpy_s(dest, destsize, src, count);
  return dest;
#else
  size_t srclen = OVR_wcslen(src);
  size_t l = Alg::Min(srclen, count);
  l = (l < destsize) ? l : destsize;
  memcpy(dest, src, l * sizeof(wchar_t));
  if (count > srclen) {
    size_t remLen = Alg::Min(destsize - l, (count - srclen));
    memset(&dest[l], 0, sizeof(wchar_t) * remLen);
  } else if (l < destsize)
    dest[l] = 0;
  return dest;
#endif
}

wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, size_t destsize, const wchar_t* src) {
#if defined(OVR_MSVC_SAFESTRING)
  wcscat_s(dest, destsize, src);
  return dest;
#elif defined(OVR_OS_MS)
  OVR_UNUSED(destsize);
  wcscat(dest, src);
  return dest;
#else
  size_t dstlen = OVR_wcslen(dest); // do not incl term null
  size_t srclen = OVR_wcslen(src) + 1; // incl term null
  size_t copylen = (dstlen + srclen < destsize) ? srclen : destsize - dstlen;
  memcpy(dest + dstlen, src, copylen * sizeof(wchar_t));
  return dest;
#endif
}

size_t OVR_CDECL OVR_wcslen(const wchar_t* str) {
#if defined(OVR_OS_MS)
  return wcslen(str);
#else
  size_t i = 0;
  while (str[i] != '\0')
    ++i;
  return i;
#endif
}

int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b) {
#if defined(OVR_OS_MS) || defined(OVR_OS_LINUX)
  return wcscmp(a, b);
#else
  // not supported, use custom implementation
  const wchar_t *pa = a, *pb = b;
  while (*pa && *pb) {
    wchar_t ca = *pa;
    wchar_t cb = *pb;
    if (ca < cb)
      return -1;
    else if (ca > cb)
      return 1;
    pa++;
    pb++;
  }
  if (*pa)
    return 1;
  else if (*pb)
    return -1;
  else
    return 0;
#endif
}

int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b) {
#if defined(OVR_OS_MS)
#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400)
  return ::_wcsicmp(a, b);
#else
  return ::wcsicmp(a, b);
#endif
#elif defined(OVR_OS_MAC) || defined(__CYGWIN__) || defined(OVR_OS_ANDROID) || \
    defined(OVR_OS_IPHONE)
  // not supported, use custom implementation
  const wchar_t *pa = a, *pb = b;
  while (*pa && *pb) {
    wchar_t ca = OVR_towlower(*pa);
    wchar_t cb = OVR_towlower(*pb);
    if (ca < cb)
      return -1;
    else if (ca > cb)
      return 1;
    pa++;
    pb++;
  }
  if (*pa)
    return 1;
  else if (*pb)
    return -1;
  else
    return 0;
#else
  return wcscasecmp(a, b);
#endif
}

// This function is not inline because of dependency on <locale.h>
double OVR_CDECL OVR_strtod(const char* str, char** tailptr) {
#if !defined(OVR_OS_ANDROID) // The Android C library doesn't have localeconv.
  const char s = *localeconv()->decimal_point;

  // Always do the locale switch to spot problem files early.
  {
    // I don't know why 347, that's just what was in this code before I got here.
    const int MaxStringLength = 347;
    OVR_ASSERT(OVR_strlen(str) <= MaxStringLength);
    char buffer[MaxStringLength + 1];
    OVR_strcpy(buffer, sizeof(buffer), str);

    // Ensure null-termination of string
    buffer[sizeof(buffer) - 1] = '\0';

    for (char* c = buffer; *c != '\0'; ++c) {
      if (*c == '.') {
        *c = s;
        break;
      }
    }

    char* nextPtr = NULL;
    double retval = strtod(buffer, &nextPtr);

    // If a tail pointer is requested,
    if (tailptr) {
      // Return a tail pointer that points to the same offset as nextPtr, in the orig string
      *tailptr = !nextPtr ? NULL : (char*)str + (int)(nextPtr - buffer);
    }

    return retval;
  }
#else
  return strtod(str, tailptr);
#endif
}

#ifndef OVR_NO_WCTYPE

//// Use this class to generate Unicode bitsets. For example:
////
//// UnicodeBitSet bitSet;
//// for(unsigned i = 0; i < 65536; ++i)
//// {
////     if (iswalpha(i))
////         bitSet.Set(i);
//// }
//// bitSet.Dump();
////
////---------------------------------------------------------------
// class UnicodeBitSet
//{
// public:
//    UnicodeBitSet()
//    {
//        memset(Offsets, 0, sizeof(Offsets));
//        memset(Bits,    0, sizeof(Bits));
//    }
//
//    void Set(unsigned bit) { Bits[bit >> 8][(bit >> 4) & 15] |= 1 << (bit & 15); }
//
//    void Dump()
//    {
//        unsigned i, j;
//        unsigned offsetCount = 0;
//        for(i = 0; i < 256; ++i)
//        {
//            if (isNull(i)) Offsets[i] = 0;
//            else
//            if (isFull(i)) Offsets[i] = 1;
//            else           Offsets[i] = uint16_t(offsetCount++ * 16 + 256);
//        }
//        for(i = 0; i < 16; ++i)
//        {
//            for(j = 0; j < 16; ++j)
//            {
//                printf("%5u,", Offsets[i*16+j]);
//            }
//            printf("\n");
//        }
//        for(i = 0; i < 256; ++i)
//        {
//            if (Offsets[i] > 255)
//            {
//                for(j = 0; j < 16; j++)
//                {
//                    printf("%5u,", Bits[i][j]);
//                }
//                printf("\n");
//            }
//        }
//    }
//
// private:
//    bool isNull(unsigned n) const
//    {
//        const uint16_t* p = Bits[n];
//        for(unsigned i = 0; i < 16; ++i)
//            if (p[i] != 0) return false;
//        return true;
//    }
//
//    bool isFull(unsigned n) const
//    {
//        const uint16_t* p = Bits[n];
//        for(unsigned i = 0; i < 16; ++i)
//            if (p[i] != 0xFFFF) return false;
//        return true;
//    }
//
//    uint16_t Offsets[256];
//    uint16_t Bits[256][16];
//};

const uint16_t UnicodeAlnumBits[] = {
    256,   1,     272,   288,   304,   320,   336,   352,   0,     368,   384,   400,   416,
    432,   448,   464,   480,   496,   512,   528,   544,   1,     560,   576,   592,   0,
    0,     0,     0,     0,     608,   624,   640,   656,   0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     672,   688,   0,     0,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     704,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     720,   1,     1,     1,     1,     736,   0,     0,     0,     0,
    0,     0,     0,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     752,   0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     1,     768,   784,   1,     800,   816,   832,   0,     0,     0,     1023,
    65534, 2047,  65534, 2047,  0,     0,     0,     524,   65535, 65407, 65535, 65407, 65535,
    65535, 65532, 15,    0,     65535, 65535, 65535, 65535, 65535, 16383, 63999, 3,     0,
    16415, 0,     0,     0,     0,     0,     32,    0,     0,     1024,  55104, 65535, 65531,
    65535, 32767, 64767, 65535, 15,    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    61443, 65535, 65535, 65535, 6559,  65535, 65535, 831,   0,     0,     0,     65534, 65535,
    639,   65534, 65535, 255,   0,     0,     0,     0,     65535, 2047,  7,     0,     0,
    65534, 2047,  65534, 63,    1023,  65535, 65535, 65535, 65535, 65535, 65535, 8175,  8702,
    8191,  0,     65535, 8191,  65535, 0,     0,     0,     0,     65535, 65535, 65535, 1,
    0,     0,     0,     0,     65518, 65535, 65535, 58367, 8191,  65281, 65487, 0,     40942,
    65529, 65023, 50117, 6559,  45184, 65487, 3,     34788, 65529, 65023, 50029, 6535,  24064,
    65472, 31,    45038, 65531, 65023, 58349, 7103,  1,     65473, 0,     40942, 65529, 65023,
    58317, 6543,  45248, 65475, 0,     51180, 54845, 50968, 50111, 7623,  128,   65408, 0,
    57326, 65533, 65023, 50159, 7647,  96,    65475, 0,     57324, 65533, 65023, 50159, 7647,
    16480, 65475, 0,     57324, 65533, 65023, 50175, 7631,  128,   65475, 0,     65516, 64639,
    65535, 12283, 32895, 65375, 0,     12,    65534, 65535, 65535, 2047,  32767, 1023,  0,
    0,     9622,  65264, 60590, 15359, 8223,  13311, 0,     0,     1,     0,     1023,  0,
    65279, 65535, 2047,  65534, 3843,  65279, 65535, 8191,  0,     0,     0,     0,     65535,
    65535, 63227, 327,   1023,  1023,  0,     0,     0,     0,     65535, 65535, 63,    65535,
    65535, 127,   65535, 65535, 65535, 65535, 65535, 33791, 65535, 65535, 65535, 65535, 65287,
    65535, 65535, 65535, 65535, 1023,  65407, 65535, 65535, 65535, 15743, 15743, 65535, 65535,
    15743, 65535, 32767, 32573, 32573, 65407, 32767, 65535, 32767, 32573, 65535, 65535, 65407,
    2047,  65024, 3,     0,     0,     65535, 65535, 65535, 65535, 65535, 31,    65534, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 40959, 127,   65534, 2047,  65535, 65535,
    65535, 65535, 2047,  0,     0,     0,     0,     0,     0,     0,     0,     0,     65535,
    65535, 65535, 65535, 511,   0,     1023,  0,     0,     1023,  65535, 65535, 65527, 65535,
    65535, 255,   65535, 65535, 1023,  0,     0,     0,     0,     0,     65535, 65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 4095,  65535, 65535, 65535, 65535, 65535, 1023,
    65535, 16191, 65535, 65535, 16191, 43775, 65535, 16383, 65535, 65535, 65535, 24543, 8156,
    4047,  8191,  8156,  0,     0,     0,     0,     0,     0,     0,     32768, 0,     0,
    0,     0,     0,     0,     0,     0,     64644, 15919, 48464, 1019,  0,     0,     65535,
    65535, 15,    0,     0,     0,     0,     0,     0,     0,     192,   0,     1022,  1792,
    65534, 65535, 65535, 65535, 65535, 31,    65534, 65535, 65535, 65535, 65535, 2047,  65504,
    65535, 8191,  65534, 65535, 65535, 65535, 65535, 32767, 0,     65535, 255,   0,     0,
    0,     0,     65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    63,    0,     0,     0,     0,     65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    65535, 65535, 63,    0,     0,     0,     0,     0,     65535, 65535, 65535, 65535, 65535,
    65535, 65535, 65535, 8191,  0,     0,     0,     0,     0,     0,     0,     65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 15,    0,     0,     0,     0,
    0,     65535, 65535, 16383, 0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     127,   41208, 65023, 24447, 65499, 65535, 65535, 65535, 65535,
    65535, 65535, 3,     0,     65528, 65535, 65535, 65535, 65535, 65535, 16383, 0,     65535,
    65535, 65535, 65535, 65532, 65535, 65535, 255,   0,     0,     4095,  0,     0,     0,
    0,     0,     0,     0,     65495, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 8191,
    0,     1023,  65534, 2047,  65534, 2047,  65472, 65534, 65535, 16383, 65535, 32767, 64764,
    7420,  0,     0};

const uint16_t UnicodeAlphaBits[] = {
    256,   1,     272,   288,   304,   320,   336,   352,   0,     368,   384,   400,   416,
    432,   448,   464,   480,   496,   512,   528,   544,   1,     560,   576,   592,   0,
    0,     0,     0,     0,     608,   624,   640,   656,   0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     672,   688,   0,     0,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     704,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     720,   1,     1,     1,     1,     736,   0,     0,     0,     0,
    0,     0,     0,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    1,     1,     1,     1,     1,     1,     1,     752,   0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     1,     768,   784,   1,     800,   816,   832,   0,     0,     0,     0,
    65534, 2047,  65534, 2047,  0,     0,     0,     0,     65535, 65407, 65535, 65407, 65535,
    65535, 65532, 15,    0,     65535, 65535, 65535, 65535, 65535, 16383, 63999, 3,     0,
    16415, 0,     0,     0,     0,     0,     32,    0,     0,     1024,  55104, 65535, 65531,
    65535, 32767, 64767, 65535, 15,    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    61443, 65535, 65535, 65535, 6559,  65535, 65535, 831,   0,     0,     0,     65534, 65535,
    639,   65534, 65535, 255,   0,     0,     0,     0,     65535, 2047,  7,     0,     0,
    65534, 2047,  65534, 63,    0,     65535, 65535, 65535, 65535, 65535, 65535, 8175,  8702,
    7168,  0,     65535, 8191,  65535, 0,     0,     0,     0,     65535, 65535, 65535, 1,
    0,     0,     0,     0,     65518, 65535, 65535, 58367, 8191,  65281, 15,    0,     40942,
    65529, 65023, 50117, 6559,  45184, 15,    3,     34788, 65529, 65023, 50029, 6535,  24064,
    0,     31,    45038, 65531, 65023, 58349, 7103,  1,     1,     0,     40942, 65529, 65023,
    58317, 6543,  45248, 3,     0,     51180, 54845, 50968, 50111, 7623,  128,   0,     0,
    57326, 65533, 65023, 50159, 7647,  96,    3,     0,     57324, 65533, 65023, 50159, 7647,
    16480, 3,     0,     57324, 65533, 65023, 50175, 7631,  128,   3,     0,     65516, 64639,
    65535, 12283, 32895, 65375, 0,     12,    65534, 65535, 65535, 2047,  32767, 0,     0,
    0,     9622,  65264, 60590, 15359, 8223,  12288, 0,     0,     1,     0,     0,     0,
    65279, 65535, 2047,  65534, 3843,  65279, 65535, 8191,  0,     0,     0,     0,     65535,
    65535, 63227, 327,   0,     1023,  0,     0,     0,     0,     65535, 65535, 63,    65535,
    65535, 127,   65535, 65535, 65535, 65535, 65535, 33791, 65535, 65535, 65535, 65535, 65287,
    65535, 65535, 65535, 65535, 1023,  65407, 65535, 65535, 65535, 15743, 15743, 65535, 65535,
    15743, 65535, 32767, 32573, 32573, 65407, 32767, 65535, 32767, 32573, 65535, 65535, 65407,
    2047,  0,     0,     0,     0,     65535, 65535, 65535, 65535, 65535, 31,    65534, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 40959, 127,   65534, 2047,  65535, 65535,
    65535, 65535, 2047,  0,     0,     0,     0,     0,     0,     0,     0,     0,     65535,
    65535, 65535, 65535, 511,   0,     0,     0,     0,     0,     65535, 65535, 65527, 65535,
    65535, 255,   65535, 65535, 1023,  0,     0,     0,     0,     0,     65535, 65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 4095,  65535, 65535, 65535, 65535, 65535, 1023,
    65535, 16191, 65535, 65535, 16191, 43775, 65535, 16383, 65535, 65535, 65535, 24543, 8156,
    4047,  8191,  8156,  0,     0,     0,     0,     0,     0,     0,     32768, 0,     0,
    0,     0,     0,     0,     0,     0,     64644, 15919, 48464, 1019,  0,     0,     65535,
    65535, 15,    0,     0,     0,     0,     0,     0,     0,     192,   0,     1022,  1792,
    65534, 65535, 65535, 65535, 65535, 31,    65534, 65535, 65535, 65535, 65535, 2047,  65504,
    65535, 8191,  65534, 65535, 65535, 65535, 65535, 32767, 0,     65535, 255,   0,     0,
    0,     0,     65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    63,    0,     0,     0,     0,     65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
    65535, 65535, 63,    0,     0,     0,     0,     0,     65535, 65535, 65535, 65535, 65535,
    65535, 65535, 65535, 8191,  0,     0,     0,     0,     0,     0,     0,     65535, 65535,
    65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 15,    0,     0,     0,     0,
    0,     65535, 65535, 16383, 0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     127,   41208, 65023, 24447, 65499, 65535, 65535, 65535, 65535,
    65535, 65535, 3,     0,     65528, 65535, 65535, 65535, 65535, 65535, 16383, 0,     65535,
    65535, 65535, 65535, 65532, 65535, 65535, 255,   0,     0,     4095,  0,     0,     0,
    0,     0,     0,     0,     65495, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 8191,
    0,     0,     65534, 2047,  65534, 2047,  65472, 65534, 65535, 16383, 65535, 32767, 64764,
    7420,  0,     0};

const uint16_t UnicodeDigitBits[] = {
    256, 0,    0,    0,    0,    0,    272,   0,   0,   288, 304, 320, 336, 352,  368,   384,
    400, 0,    0,    416,  0,    0,    0,     432, 448, 0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     464,
    0,   0,    0,    1023, 0,    0,    0,     0,   0,   0,   0,   524, 0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    1023,  0,   0,   0,   0,   0,   0,   0,    0,     1023,
    0,   0,    0,    0,    0,    0,    65472, 0,   0,   0,   0,   0,   0,   0,    65472, 0,
    0,   0,    0,    0,    0,    0,    65472, 0,   0,   0,   0,   0,   0,   0,    65472, 0,
    0,   0,    0,    0,    0,    0,    65472, 0,   0,   0,   0,   0,   0,   0,    65408, 0,
    0,   0,    0,    0,    0,    0,    65472, 0,   0,   0,   0,   0,   0,   0,    65472, 0,
    0,   0,    0,    0,    0,    0,    65472, 0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    1023, 0,     0,   0,   0,   0,   0,   0,   1023, 0,     0,
    0,   0,    1023, 0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    1023, 0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    65024, 3,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   0,    0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    1023,  0,
    0,   1023, 0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0,
    0,   1023, 0,    0,    0,    0,    0,     0,   0,   0,   0,   0,   0,   0,    0,     0};

const uint16_t UnicodeSpaceBits[] = {
    256, 0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 272, 0,   0,
    0,   0, 0, 0, 0, 0, 0,     288, 0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   304, 0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 0, 15872, 0,   1, 0, 0, 0, 0, 0,    0, 0,     1, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 0, 1, 0,     0,   0, 0, 0, 0, 0, 4095, 0, 33536, 0, 0, 0, 0, 0, 0, 0,   0,   0,
    0,   0, 0, 0, 1, 0, 0,     0,   0, 0, 0, 0, 0, 0,    0, 0,     0, 0, 0, 0};

const uint16_t UnicodeXDigitBits[] = {
    256, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 0,    0,   0, 0,   0, 0, 272, 0, 0, 0, 1023, 126, 0, 126, 0,
    0,   0, 0, 0, 0, 0, 0, 0, 0, 1023, 126, 0, 126, 0, 0, 0,   0, 0, 0, 0,    0,   0, 0,   0};

// Uncomment if necessary
// const uint16_t UnicodeCntrlBits[] = {
//  256,    0,    0,    0,    0,    0,    0,  272,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,  288,    0,    0,    0,    0,    0,    0,    0,
//  304,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  320,  336,
// 65535,65535,    0,    0,    0,    0,    0,32768,65535,65535,    0,    0,    0,    0,    0,    0,
// 32768,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 30720,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 61440,    0,31744,    0,    0,    0,64512,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,32768,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 3584};
//
// const uint16_t UnicodeGraphBits[] = {
//  256,    1,  272,  288,  304,  320,  336,  352,    0,  368,  384,  400,  416,  432,  448,  464,
//  480,  496,  512,  528,  544,    1,  560,  576,  592,    0,    0,    0,    0,    0,  608,  624,
//  640,  656,    0,  672,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  688,  704,    0,    0,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,  720,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,  736,
//    1,    1,    1,    1,  752,    0,    0,    0,    0,    0,    0,    0,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,  768,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,  784,  800,    1,  816,  832,  848,
//    0,    0,65534,65535,65535,65535,65535,32767,    0,    0,65534,65535,65535,65535,65535,65535,
// 65535,65535,65532,   15,    0,65535,65535,65535,65535,65535,16383,63999,    3,    0,16415,    0,
//    0,    0,    0,    0,   32,    0,    0,17408,55232,65535,65531,65535,32767,64767,65535,   15,
// 65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535,  831,
//    0,    0,    0,65534,65535,65151,65534,65535, 1791,    0,    0,16384,    9,65535, 2047,   31,
// 4096,34816,65534, 2047,65534,   63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
// 16383,65535, 8191,65535,    0,    0,    0,    0,65535,65535,65535,    1,    0,    0,    0,    0,
// 65518,65535,65535,58367, 8191,65281,65535,    1,40942,65529,65023,50117, 6559,45184,65487,    3,
// 34788,65529,65023,50029, 6535,24064,65472,   31,45038,65531,65023,58349, 7103,    1,65473,    0,
// 40942,65529,65023,58317, 6543,45248,65475,    0,51180,54845,50968,50111, 7623,  128,65408,    0,
// 57326,65533,65023,50159, 7647,   96,65475,    0,57324,65533,65023,50159, 7647,16480,65475,    0,
// 57324,65533,65023,50175, 7631,  128,65475,    0,65516,64639,65535,12283,32895,65375,    0,   28,
// 65534,65535,65535, 2047,65535, 4095,    0,    0, 9622,65264,60590,15359, 8223,13311,    0,    0,
// 65521,    7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191,    0,    0,    0,    0,
// 65535,65535,63227,  327,65535, 1023,    0,    0,    0,    0,65535,65535,   63,65535,65535, 2175,
// 65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
// 65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
// 32767,32573,65535,65535,65407, 2047,65534,    3,    0,    0,65535,65535,65535,65535,65535,   31,
// 65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
// 65535,65535,65535,65535,65535,65535,65535,  127,65534, 8191,65535,65535,65535,65535,16383,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,65535,65535,65535,65535,  511, 6128, 1023,    0,
// 2047, 1023,65535,65535,65527,65535,65535,  255,65535,65535, 1023,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
// 65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
//    0,65535,  255,65535,16239,    0,    0,57344,24576,    0,    0,    0,    0,    0,    0,    0,
// 64644,15919,48464, 1019,    0,    0,65535,65535,   15,    0,    0,    0,    0,    0,    0,    0,
//    0,    0, 1536,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 65486,65523, 1022, 1793,65534,65535,65535,65535,65535,   31,65534,65535,65535,65535,65535, 4095,
// 65504,65535, 8191,65534,65535,65535,65535,65535,32767,    0,65535,  255,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   63,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   63,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535, 8191,    0,    0,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   15,    0,    0,    0,    0,    0,
// 65535,65535,16383,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535,    3,    0,65528,65535,65535,
// 65535,65535,65535,65535,    0,65535,65535,65535,65535,65532,65535,65535,  255,    0,    0, 4095,
//    0,    0,    0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535, 8191,
// 63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420,    0,    0};
//
// const uint16_t UnicodePrintBits[] = {
//  256,    1,  272,  288,  304,  320,  336,  352,    0,  368,  384,  400,  416,  432,  448,  464,
//  480,  496,  512,  528,  544,    1,  560,  576,  592,    0,    0,    0,    0,    0,  608,  624,
//  640,  656,    0,  672,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  688,  704,    0,    0,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,  720,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,  736,
//    1,    1,    1,    1,  752,    0,    0,    0,    0,    0,    0,    0,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
//    1,    1,    1,    1,    1,    1,    1,  768,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,  784,  800,    1,  816,  832,  848,
//  512,    0,65535,65535,65535,65535,65535,32767,    0,    0,65535,65535,65535,65535,65535,65535,
// 65535,65535,65532,   15,    0,65535,65535,65535,65535,65535,16383,63999,    3,    0,16415,    0,
//    0,    0,    0,    0,   32,    0,    0,17408,55232,65535,65531,65535,32767,64767,65535,   15,
// 65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535,  831,
//    0,    0,    0,65534,65535,65151,65534,65535, 1791,    0,    0,16384,    9,65535, 2047,   31,
// 4096,34816,65534, 2047,65534,   63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191,
// 16383,65535, 8191,65535,    0,    0,    0,    0,65535,65535,65535,    1,    0,    0,    0,    0,
// 65518,65535,65535,58367, 8191,65281,65535,    1,40942,65529,65023,50117, 6559,45184,65487,    3,
// 34788,65529,65023,50029, 6535,24064,65472,   31,45038,65531,65023,58349, 7103,    1,65473,    0,
// 40942,65529,65023,58317, 6543,45248,65475,    0,51180,54845,50968,50111, 7623,  128,65408,    0,
// 57326,65533,65023,50159, 7647,   96,65475,    0,57324,65533,65023,50159, 7647,16480,65475,    0,
// 57324,65533,65023,50175, 7631,  128,65475,    0,65516,64639,65535,12283,32895,65375,    0,   28,
// 65534,65535,65535, 2047,65535, 4095,    0,    0, 9622,65264,60590,15359, 8223,13311,    0,    0,
// 65521,    7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191,    0,    0,    0,    0,
// 65535,65535,63227,  327,65535, 1023,    0,    0,    0,    0,65535,65535,   63,65535,65535, 2175,
// 65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023,
// 65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535,
// 32767,32573,65535,65535,65407, 2047,65534,    3,    0,    0,65535,65535,65535,65535,65535,   31,
// 65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,
// 65535,65535,65535,65535,65535,65535,65535,  127,65534, 8191,65535,65535,65535,65535,16383,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,65535,65535,65535,65535,  511, 6128, 1023,    0,
// 2047, 1023,65535,65535,65527,65535,65535,  255,65535,65535, 1023,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023,
// 65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156,
//    0,65535,  255,65535,16239,    0,    0,57344,24576,    0,    0,    0,    0,    0,    0,    0,
// 64644,15919,48464, 1019,    0,    0,65535,65535,   15,    0,    0,    0,    0,    0,    0,    0,
//    0,    0, 1536,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 65487,65523, 1022, 1793,65534,65535,65535,65535,65535,   31,65534,65535,65535,65535,65535, 4095,
// 65504,65535, 8191,65534,65535,65535,65535,65535,32767,    0,65535,  255,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   63,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   63,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535, 8191,    0,    0,    0,    0,    0,    0,    0,
// 65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,   15,    0,    0,    0,    0,    0,
// 65535,65535,16383,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535,    3,    0,65528,65535,65535,
// 65535,65535,65535,65535,    0,65535,65535,65535,65535,65532,65535,65535,  255,    0,    0, 4095,
//    0,    0,    0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535,40959,
// 63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420,    0,    0};
//
// const uint16_t UnicodePunctBits[] = {
//  256,    0,    0,  272,    0,  288,  304,  320,    0,  336,    0,    0,    0,  352,  368,  384,
//  400,    0,    0,  416,    0,    0,  432,  448,  464,    0,    0,    0,    0,    0,    0,    0,
//  480,    0,    0,  496,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  512,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  528,  544,  560,
//    0,    0,65534,64512,    1,63488,    1,30720,    0,    0,65534,65535,    0,  128,    0,  128,
//    0,    0,    0,    0,    0,    0,    0,16384,  128,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,64512,    0,    0, 1536,    0,    0,16384,    9,    0,    0,   24,
// 4096,34816,    0,    0,    0,    0,15360,    0,    0,    0,    0,    0,    0,   16,    0,    0,
// 16383,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,   48,    1,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   16,
//    0,    0,    0,    0,32768, 3072,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 65520,    7,    0,15360,    0,    0,    0,    0,   32,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,64512,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 2048,
//    0,    0,    0,    0,    0,    0,  510,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,24576,    0,    0, 6144,    0,    0,    0,    0,14336,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 6128,    0,    0,
// 2047,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,65535,  255,65535,16239,    0,    0,24576,24576,    0,    0,    0,    0,    0,    0,    0,
//    0,    0, 1536,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 65294,65523,    0,    1,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, 2048,
//    0,    0,    0,49152,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,65535,65055,65527, 3339,    0,    0,    0,    0,    0,    0,    0,    0,    0,
// 63470,35840,    1,47104,    0,10240,   62,    0,    0,    0,    0,    0,    0,    0,    0,    0};
//
// const uint16_t UnicodeLowerBits[] = {
//  256,  272,  288,  304,  320,  336,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  352,  368,
//  384,  400,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  416,    0,    0,    0,  432,
//    0,    0,    0,    0,    0,    0,65534, 2047,    0,    0,    0,    0,    0,32768,65535,65407,
// 43690,43690,43690,21930,43861,43690,43690,54442,12585,20004,11562,58961,23392,46421,43690,43565,
// 43690,43690,43688,   10,    0,65535,65535,65535,65535,65535,16383,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    1,61440,65535,32767,43235,43690,   15,
//    0,    0,    0,65535,65535,65535,43690,43690,40962,43690,43690,43690, 4372,43690,43690,  554,
//    0,    0,    0,    0,    0,    0,65534,65535,  255,    0,    0,    0,    0,    0,    0,    0,
// 43690,43690,43690,43690,43690,43690,43690,43690,43690, 4074,43690,43690,43690,43690,43690,  682,
//  255,   63,  255,  255,   63,  255,  255,16383,65535,65535,65535,20703, 4316,  207,  255, 4316,
//    0,    0,    0,    0,    0,    0,    0,32768,    0,    0,    0,    0,    0,    0,    0,    0,
// 50176,    8,32768,  528,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  127,  248,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,65534, 2047,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0};
//
// const uint16_t UnicodeUpperBits[] = {
//  256,  272,  288,  304,  320,  336,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//  352,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  368,  384,
//    0,  400,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,  416,
//    0,    0,    0,    0,65534, 2047,    0,    0,    0,    0,    0,    0,65535,32639,    0,    0,
// 21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53973, 4526,44464,19114,21845,21974,
// 21845,21845,21844,    5,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,55104,65534, 4091,    0,    0,21532,21845,    0,
// 65535,65535,65535,    0,    0,    0,21845,21845,20481,21845,21845,21845, 2187,21845,21845,  277,
//    0,    0,    0,65534,65535,  127,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,65535,65535,   63,    0,    0,    0,
// 21845,21845,21845,21845,21845,21845,21845,21845,21845,   21,21845,21845,21845,21845,21845,  341,
// 65280,16128,65280,65280,16128,43520,65280,    0,65280,65280,65280, 7936, 7936, 3840, 7936, 7936,
// 14468,15911,15696,   11,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
//    0,    0,65534, 2047,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0};

// MA: March 19, 2010
// Modified ToUpper and ToLower tables to match values expected by AS3 tests.
// ToLower modifications:
//    304 ->  105
//   1024 -> 1104 *
//   1037 -> 1117 *
// UoUpper modifications:
//    255 ->  376
//    305 ->   73
//    383 ->   83
//   1104 -> 1024 *
//   1117 -> 1037 *
// Entries marked with a '*' don't make complete sense based on Unicode manual, although
// they match AS3.

static const uint16_t UnicodeToUpperBits[] = {
    256,   272,   288,   304,   320,   336,   0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     352,   368,   0,     384,   0,     0,     400,   0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     416,   0,     0,     0,     0,
    0,     0,     65534, 2047,  0,     0,     0,     0,     0,     0,     65535, 65407, 43690,
    43690, 43690, 21674, 43349, 43690, 43690, 54442, 4392,  516,   8490,  8785,  21056, 46421,
    43690, 43048, // MA: Modified for AS3.
    43690, 170,   0,     0,     0,     2776,  33545, 36,    3336,  4,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    61440, 65534, 32767, 0,     43688, 0,     0,     0,     0,     65535, 65535, 65535, 43690,
    43690, 2,     43690, 43690, 43690, 4372,  43690, 35498, 554, // MA: Modified for AS3.
    0,     0,     0,     0,     0,     0,     65534, 65535, 127,   0,     0,     0,     0,
    0,     0,     0,     43690, 43690, 43690, 43690, 43690, 43690, 43690, 43690, 43690, 42,
    43690, 43690, 43690, 43690, 43690, 682,   255,   63,    255,   255,   63,    170,   255,
    16383, 0,     0,     0,     3,     0,     3,     35,    0,     0,     0,     0,     0,
    0,     0,     0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     65535,
    1023,  0,     0,     0,     0,     0,     65534, 2047,  0,     0,     0,     0,     0,
    0,     0,     0,     0,     0};

static const uint16_t UnicodeToLowerBits[] = {
    256,   272,   288,   304,   320,   336,   0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     352,   0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     368,   384,   0,     400,   0,     0,     416,   0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     432,   0,     0,     0,     0,
    65534, 2047,  0,     0,     0,     0,     0,     0,     65535, 32639, 0,     0,     21845,
    21845, 21845, 43605, 21674, 21845, 21845, 11093, 52950, 45531, 53909, 4526,  42128, 19114,
    21845, 21522, // MA: Modidied for AS3.
    21845, 85,    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     55104, 65534,
    4091,  0,     0,     0,     21844, 0,     65535, 65535, 65535, 0,     0,     0,     21845,
    21845, 1,     21845, 21845, 21845, 2186,  21845, 17749, 277,   0,     0,     0,     65534,
    65535, 127,   0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     65535, 65535, 63,    0,
    0,     0,     21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21845, 21,    21845,
    21845, 21845, 21845, 21845, 341,   65280, 16128, 65280, 65280, 16128, 43520, 65280, 0,
    0,     0,     0,     3840,  3840,  3840,  7936,  3840,  0,     0,     0,     0,     0,
    0,     65535, 0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0,     0,     0,     0,     0,     0,     65472, 65535, 0,     0,
    0,     0,     0,     65534, 2047,  0,     0,     0,     0,     0,     0,     0,     0,
    0,     0,     0,     0};

struct GUnicodePairType {
  uint16_t Key, Value;
};

static inline bool CmpUnicodeKey(const GUnicodePairType& a, uint16_t key) {
  return a.Key < key;
}

static const GUnicodePairType UnicodeToUpperTable[] = {
    {97, 65},       {98, 66},       {99, 67},       {100, 68},      {101, 69},      {102, 70},
    {103, 71},      {104, 72},      {105, 73},      {106, 74},      {107, 75},      {108, 76},
    {109, 77},      {110, 78},      {111, 79},      {112, 80},      {113, 81},      {114, 82},
    {115, 83},      {116, 84},      {117, 85},      {118, 86},      {119, 87},      {120, 88},
    {121, 89},      {122, 90},      {224, 192},     {225, 193},     {226, 194},     {227, 195},
    {228, 196},     {229, 197},     {230, 198},     {231, 199},     {232, 200},     {233, 201},
    {234, 202},     {235, 203},     {236, 204},     {237, 205},     {238, 206},     {239, 207},
    {240, 208},     {241, 209},     {242, 210},     {243, 211},     {244, 212},     {245, 213},
    {246, 214},     {248, 216},     {249, 217},     {250, 218},     {251, 219},     {252, 220},
    {253, 221},     {254, 222},     {255, 376},     {257, 256},     {259, 258},     {261, 260},
    {263, 262},     {265, 264},     {267, 266},     {269, 268},     {271, 270},     {273, 272},
    {275, 274},     {277, 276},     {279, 278},     {281, 280},     {283, 282},     {285, 284},
    {287, 286},     {289, 288},     {291, 290},     {293, 292},     {295, 294},     {297, 296},
    {299, 298},     {301, 300},     {303, 302},     {305, 73},      {307, 306},     {309, 308},
    {311, 310},     {314, 313},     {316, 315},     {318, 317},     {320, 319},     {322, 321},
    {324, 323},     {326, 325},     {328, 327},     {331, 330},     {333, 332},     {335, 334},
    {337, 336},     {339, 338},     {341, 340},     {343, 342},     {345, 344},     {347, 346},
    {349, 348},     {351, 350},     {353, 352},     {355, 354},     {357, 356},     {359, 358},
    {361, 360},     {363, 362},     {365, 364},     {367, 366},     {369, 368},     {371, 370},
    {373, 372},     {375, 374},     {378, 377},     {380, 379},     {382, 381},     {383, 83},
    {387, 386},     {389, 388},     {392, 391},     {396, 395},     {402, 401},     {409, 408},
    {417, 416},     {419, 418},     {421, 420},     {424, 423},     {429, 428},     {432, 431},
    {436, 435},     {438, 437},     {441, 440},     {445, 444},     {454, 452},     {457, 455},
    {460, 458},     {462, 461},     {464, 463},     {466, 465},     {468, 467},     {470, 469},
    {472, 471},     {474, 473},     {476, 475},     {477, 398},     {479, 478},     {481, 480},
    {483, 482},     {485, 484},     {487, 486},     {489, 488},     {491, 490},     {493, 492},
    {495, 494},     {499, 497},     {501, 500},     {507, 506},     {509, 508},     {511, 510},
    {513, 512},     {515, 514},     {517, 516},     {519, 518},     {521, 520},     {523, 522},
    {525, 524},     {527, 526},     {529, 528},     {531, 530},     {533, 532},     {535, 534},
    {595, 385},     {596, 390},     {598, 393},     {599, 394},     {601, 399},     {603, 400},
    {608, 403},     {611, 404},     {616, 407},     {617, 406},     {623, 412},     {626, 413},
    {629, 415},     {643, 425},     {648, 430},     {650, 433},     {651, 434},     {658, 439},
    {940, 902},     {941, 904},     {942, 905},     {943, 906},     {945, 913},     {946, 914},
    {947, 915},     {948, 916},     {949, 917},     {950, 918},     {951, 919},     {952, 920},
    {953, 921},     {954, 922},     {955, 923},     {956, 924},     {957, 925},     {958, 926},
    {959, 927},     {960, 928},     {961, 929},     {962, 931},     {963, 931},     {964, 932},
    {965, 933},     {966, 934},     {967, 935},     {968, 936},     {969, 937},     {970, 938},
    {971, 939},     {972, 908},     {973, 910},     {974, 911},     {995, 994},     {997, 996},
    {999, 998},     {1001, 1000},   {1003, 1002},   {1005, 1004},   {1007, 1006},   {1072, 1040},
    {1073, 1041},   {1074, 1042},   {1075, 1043},   {1076, 1044},   {1077, 1045},   {1078, 1046},
    {1079, 1047},   {1080, 1048},   {1081, 1049},   {1082, 1050},   {1083, 1051},   {1084, 1052},
    {1085, 1053},   {1086, 1054},   {1087, 1055},   {1088, 1056},   {1089, 1057},   {1090, 1058},
    {1091, 1059},   {1092, 1060},   {1093, 1061},   {1094, 1062},   {1095, 1063},   {1096, 1064},
    {1097, 1065},   {1098, 1066},   {1099, 1067},   {1100, 1068},   {1101, 1069},   {1102, 1070},
    {1103, 1071},   {1104, 1024},   {1105, 1025},   {1106, 1026},   {1107, 1027},   {1108, 1028},
    {1109, 1029},   {1110, 1030},   {1111, 1031},   {1112, 1032},   {1113, 1033},   {1114, 1034},
    {1115, 1035},   {1116, 1036},   {1117, 1037},   {1118, 1038},   {1119, 1039},   {1121, 1120},
    {1123, 1122},   {1125, 1124},   {1127, 1126},   {1129, 1128},   {1131, 1130},   {1133, 1132},
    {1135, 1134},   {1137, 1136},   {1139, 1138},   {1141, 1140},   {1143, 1142},   {1145, 1144},
    {1147, 1146},   {1149, 1148},   {1151, 1150},   {1153, 1152},   {1169, 1168},   {1171, 1170},
    {1173, 1172},   {1175, 1174},   {1177, 1176},   {1179, 1178},   {1181, 1180},   {1183, 1182},
    {1185, 1184},   {1187, 1186},   {1189, 1188},   {1191, 1190},   {1193, 1192},   {1195, 1194},
    {1197, 1196},   {1199, 1198},   {1201, 1200},   {1203, 1202},   {1205, 1204},   {1207, 1206},
    {1209, 1208},   {1211, 1210},   {1213, 1212},   {1215, 1214},   {1218, 1217},   {1220, 1219},
    {1224, 1223},   {1228, 1227},   {1233, 1232},   {1235, 1234},   {1237, 1236},   {1239, 1238},
    {1241, 1240},   {1243, 1242},   {1245, 1244},   {1247, 1246},   {1249, 1248},   {1251, 1250},
    {1253, 1252},   {1255, 1254},   {1257, 1256},   {1259, 1258},   {1263, 1262},   {1265, 1264},
    {1267, 1266},   {1269, 1268},   {1273, 1272},   {1377, 1329},   {1378, 1330},   {1379, 1331},
    {1380, 1332},   {1381, 1333},   {1382, 1334},   {1383, 1335},   {1384, 1336},   {1385, 1337},
    {1386, 1338},   {1387, 1339},   {1388, 1340},   {1389, 1341},   {1390, 1342},   {1391, 1343},
    {1392, 1344},   {1393, 1345},   {1394, 1346},   {1395, 1347},   {1396, 1348},   {1397, 1349},
    {1398, 1350},   {1399, 1351},   {1400, 1352},   {1401, 1353},   {1402, 1354},   {1403, 1355},
    {1404, 1356},   {1405, 1357},   {1406, 1358},   {1407, 1359},   {1408, 1360},   {1409, 1361},
    {1410, 1362},   {1411, 1363},   {1412, 1364},   {1413, 1365},   {1414, 1366},   {7681, 7680},
    {7683, 7682},   {7685, 7684},   {7687, 7686},   {7689, 7688},   {7691, 7690},   {7693, 7692},
    {7695, 7694},   {7697, 7696},   {7699, 7698},   {7701, 7700},   {7703, 7702},   {7705, 7704},
    {7707, 7706},   {7709, 7708},   {7711, 7710},   {7713, 7712},   {7715, 7714},   {7717, 7716},
    {7719, 7718},   {7721, 7720},   {7723, 7722},   {7725, 7724},   {7727, 7726},   {7729, 7728},
    {7731, 7730},   {7733, 7732},   {7735, 7734},   {7737, 7736},   {7739, 7738},   {7741, 7740},
    {7743, 7742},   {7745, 7744},   {7747, 7746},   {7749, 7748},   {7751, 7750},   {7753, 7752},
    {7755, 7754},   {7757, 7756},   {7759, 7758},   {7761, 7760},   {7763, 7762},   {7765, 7764},
    {7767, 7766},   {7769, 7768},   {7771, 7770},   {7773, 7772},   {7775, 7774},   {7777, 7776},
    {7779, 7778},   {7781, 7780},   {7783, 7782},   {7785, 7784},   {7787, 7786},   {7789, 7788},
    {7791, 7790},   {7793, 7792},   {7795, 7794},   {7797, 7796},   {7799, 7798},   {7801, 7800},
    {7803, 7802},   {7805, 7804},   {7807, 7806},   {7809, 7808},   {7811, 7810},   {7813, 7812},
    {7815, 7814},   {7817, 7816},   {7819, 7818},   {7821, 7820},   {7823, 7822},   {7825, 7824},
    {7827, 7826},   {7829, 7828},   {7841, 7840},   {7843, 7842},   {7845, 7844},   {7847, 7846},
    {7849, 7848},   {7851, 7850},   {7853, 7852},   {7855, 7854},   {7857, 7856},   {7859, 7858},
    {7861, 7860},   {7863, 7862},   {7865, 7864},   {7867, 7866},   {7869, 7868},   {7871, 7870},
    {7873, 7872},   {7875, 7874},   {7877, 7876},   {7879, 7878},   {7881, 7880},   {7883, 7882},
    {7885, 7884},   {7887, 7886},   {7889, 7888},   {7891, 7890},   {7893, 7892},   {7895, 7894},
    {7897, 7896},   {7899, 7898},   {7901, 7900},   {7903, 7902},   {7905, 7904},   {7907, 7906},
    {7909, 7908},   {7911, 7910},   {7913, 7912},   {7915, 7914},   {7917, 7916},   {7919, 7918},
    {7921, 7920},   {7923, 7922},   {7925, 7924},   {7927, 7926},   {7929, 7928},   {7936, 7944},
    {7937, 7945},   {7938, 7946},   {7939, 7947},   {7940, 7948},   {7941, 7949},   {7942, 7950},
    {7943, 7951},   {7952, 7960},   {7953, 7961},   {7954, 7962},   {7955, 7963},   {7956, 7964},
    {7957, 7965},   {7968, 7976},   {7969, 7977},   {7970, 7978},   {7971, 7979},   {7972, 7980},
    {7973, 7981},   {7974, 7982},   {7975, 7983},   {7984, 7992},   {7985, 7993},   {7986, 7994},
    {7987, 7995},   {7988, 7996},   {7989, 7997},   {7990, 7998},   {7991, 7999},   {8000, 8008},
    {8001, 8009},   {8002, 8010},   {8003, 8011},   {8004, 8012},   {8005, 8013},   {8017, 8025},
    {8019, 8027},   {8021, 8029},   {8023, 8031},   {8032, 8040},   {8033, 8041},   {8034, 8042},
    {8035, 8043},   {8036, 8044},   {8037, 8045},   {8038, 8046},   {8039, 8047},   {8048, 8122},
    {8049, 8123},   {8050, 8136},   {8051, 8137},   {8052, 8138},   {8053, 8139},   {8054, 8154},
    {8055, 8155},   {8056, 8184},   {8057, 8185},   {8058, 8170},   {8059, 8171},   {8060, 8186},
    {8061, 8187},   {8112, 8120},   {8113, 8121},   {8144, 8152},   {8145, 8153},   {8160, 8168},
    {8161, 8169},   {8165, 8172},   {8560, 8544},   {8561, 8545},   {8562, 8546},   {8563, 8547},
    {8564, 8548},   {8565, 8549},   {8566, 8550},   {8567, 8551},   {8568, 8552},   {8569, 8553},
    {8570, 8554},   {8571, 8555},   {8572, 8556},   {8573, 8557},   {8574, 8558},   {8575, 8559},
    {9424, 9398},   {9425, 9399},   {9426, 9400},   {9427, 9401},   {9428, 9402},   {9429, 9403},
    {9430, 9404},   {9431, 9405},   {9432, 9406},   {9433, 9407},   {9434, 9408},   {9435, 9409},
    {9436, 9410},   {9437, 9411},   {9438, 9412},   {9439, 9413},   {9440, 9414},   {9441, 9415},
    {9442, 9416},   {9443, 9417},   {9444, 9418},   {9445, 9419},   {9446, 9420},   {9447, 9421},
    {9448, 9422},   {9449, 9423},   {65345, 65313}, {65346, 65314}, {65347, 65315}, {65348, 65316},
    {65349, 65317}, {65350, 65318}, {65351, 65319}, {65352, 65320}, {65353, 65321}, {65354, 65322},
    {65355, 65323}, {65356, 65324}, {65357, 65325}, {65358, 65326}, {65359, 65327}, {65360, 65328},
    {65361, 65329}, {65362, 65330}, {65363, 65331}, {65364, 65332}, {65365, 65333}, {65366, 65334},
    {65367, 65335}, {65368, 65336}, {65369, 65337}, {65370, 65338}, {65535, 0}};

static const GUnicodePairType UnicodeToLowerTable[] = {
    {65, 97},       {66, 98},       {67, 99},       {68, 100},      {69, 101},      {70, 102},
    {71, 103},      {72, 104},      {73, 105},      {74, 106},      {75, 107},      {76, 108},
    {77, 109},      {78, 110},      {79, 111},      {80, 112},      {81, 113},      {82, 114},
    {83, 115},      {84, 116},      {85, 117},      {86, 118},      {87, 119},      {88, 120},
    {89, 121},      {90, 122},      {192, 224},     {193, 225},     {194, 226},     {195, 227},
    {196, 228},     {197, 229},     {198, 230},     {199, 231},     {200, 232},     {201, 233},
    {202, 234},     {203, 235},     {204, 236},     {205, 237},     {206, 238},     {207, 239},
    {208, 240},     {209, 241},     {210, 242},     {211, 243},     {212, 244},     {213, 245},
    {214, 246},     {216, 248},     {217, 249},     {218, 250},     {219, 251},     {220, 252},
    {221, 253},     {222, 254},     {256, 257},     {258, 259},     {260, 261},     {262, 263},
    {264, 265},     {266, 267},     {268, 269},     {270, 271},     {272, 273},     {274, 275},
    {276, 277},     {278, 279},     {280, 281},     {282, 283},     {284, 285},     {286, 287},
    {288, 289},     {290, 291},     {292, 293},     {294, 295},     {296, 297},     {298, 299},
    {300, 301},     {302, 303},     {304, 105},     {306, 307},     {308, 309},     {310, 311},
    {313, 314},     {315, 316},     {317, 318},     {319, 320},     {321, 322},     {323, 324},
    {325, 326},     {327, 328},     {330, 331},     {332, 333},     {334, 335},     {336, 337},
    {338, 339},     {340, 341},     {342, 343},     {344, 345},     {346, 347},     {348, 349},
    {350, 351},     {352, 353},     {354, 355},     {356, 357},     {358, 359},     {360, 361},
    {362, 363},     {364, 365},     {366, 367},     {368, 369},     {370, 371},     {372, 373},
    {374, 375},     {376, 255},     {377, 378},     {379, 380},     {381, 382},     {385, 595},
    {386, 387},     {388, 389},     {390, 596},     {391, 392},     {393, 598},     {394, 599},
    {395, 396},     {398, 477},     {399, 601},     {400, 603},     {401, 402},     {403, 608},
    {404, 611},     {406, 617},     {407, 616},     {408, 409},     {412, 623},     {413, 626},
    {415, 629},     {416, 417},     {418, 419},     {420, 421},     {423, 424},     {425, 643},
    {428, 429},     {430, 648},     {431, 432},     {433, 650},     {434, 651},     {435, 436},
    {437, 438},     {439, 658},     {440, 441},     {444, 445},     {452, 454},     {455, 457},
    {458, 460},     {461, 462},     {463, 464},     {465, 466},     {467, 468},     {469, 470},
    {471, 472},     {473, 474},     {475, 476},     {478, 479},     {480, 481},     {482, 483},
    {484, 485},     {486, 487},     {488, 489},     {490, 491},     {492, 493},     {494, 495},
    {497, 499},     {500, 501},     {506, 507},     {508, 509},     {510, 511},     {512, 513},
    {514, 515},     {516, 517},     {518, 519},     {520, 521},     {522, 523},     {524, 525},
    {526, 527},     {528, 529},     {530, 531},     {532, 533},     {534, 535},     {902, 940},
    {904, 941},     {905, 942},     {906, 943},     {908, 972},     {910, 973},     {911, 974},
    {913, 945},     {914, 946},     {915, 947},     {916, 948},     {917, 949},     {918, 950},
    {919, 951},     {920, 952},     {921, 953},     {922, 954},     {923, 955},     {924, 956},
    {925, 957},     {926, 958},     {927, 959},     {928, 960},     {929, 961},     {931, 963},
    {932, 964},     {933, 965},     {934, 966},     {935, 967},     {936, 968},     {937, 969},
    {938, 970},     {939, 971},     {994, 995},     {996, 997},     {998, 999},     {1000, 1001},
    {1002, 1003},   {1004, 1005},   {1006, 1007},   {1024, 1104},   {1025, 1105},   {1026, 1106},
    {1027, 1107},   {1028, 1108},   {1029, 1109},   {1030, 1110},   {1031, 1111},   {1032, 1112},
    {1033, 1113},   {1034, 1114},   {1035, 1115},   {1036, 1116},   {1037, 1117},   {1038, 1118},
    {1039, 1119},   {1040, 1072},   {1041, 1073},   {1042, 1074},   {1043, 1075},   {1044, 1076},
    {1045, 1077},   {1046, 1078},   {1047, 1079},   {1048, 1080},   {1049, 1081},   {1050, 1082},
    {1051, 1083},   {1052, 1084},   {1053, 1085},   {1054, 1086},   {1055, 1087},   {1056, 1088},
    {1057, 1089},   {1058, 1090},   {1059, 1091},   {1060, 1092},   {1061, 1093},   {1062, 1094},
    {1063, 1095},   {1064, 1096},   {1065, 1097},   {1066, 1098},   {1067, 1099},   {1068, 1100},
    {1069, 1101},   {1070, 1102},   {1071, 1103},   {1120, 1121},   {1122, 1123},   {1124, 1125},
    {1126, 1127},   {1128, 1129},   {1130, 1131},   {1132, 1133},   {1134, 1135},   {1136, 1137},
    {1138, 1139},   {1140, 1141},   {1142, 1143},   {1144, 1145},   {1146, 1147},   {1148, 1149},
    {1150, 1151},   {1152, 1153},   {1168, 1169},   {1170, 1171},   {1172, 1173},   {1174, 1175},
    {1176, 1177},   {1178, 1179},   {1180, 1181},   {1182, 1183},   {1184, 1185},   {1186, 1187},
    {1188, 1189},   {1190, 1191},   {1192, 1193},   {1194, 1195},   {1196, 1197},   {1198, 1199},
    {1200, 1201},   {1202, 1203},   {1204, 1205},   {1206, 1207},   {1208, 1209},   {1210, 1211},
    {1212, 1213},   {1214, 1215},   {1217, 1218},   {1219, 1220},   {1223, 1224},   {1227, 1228},
    {1232, 1233},   {1234, 1235},   {1236, 1237},   {1238, 1239},   {1240, 1241},   {1242, 1243},
    {1244, 1245},   {1246, 1247},   {1248, 1249},   {1250, 1251},   {1252, 1253},   {1254, 1255},
    {1256, 1257},   {1258, 1259},   {1262, 1263},   {1264, 1265},   {1266, 1267},   {1268, 1269},
    {1272, 1273},   {1329, 1377},   {1330, 1378},   {1331, 1379},   {1332, 1380},   {1333, 1381},
    {1334, 1382},   {1335, 1383},   {1336, 1384},   {1337, 1385},   {1338, 1386},   {1339, 1387},
    {1340, 1388},   {1341, 1389},   {1342, 1390},   {1343, 1391},   {1344, 1392},   {1345, 1393},
    {1346, 1394},   {1347, 1395},   {1348, 1396},   {1349, 1397},   {1350, 1398},   {1351, 1399},
    {1352, 1400},   {1353, 1401},   {1354, 1402},   {1355, 1403},   {1356, 1404},   {1357, 1405},
    {1358, 1406},   {1359, 1407},   {1360, 1408},   {1361, 1409},   {1362, 1410},   {1363, 1411},
    {1364, 1412},   {1365, 1413},   {1366, 1414},   {4256, 4304},   {4257, 4305},   {4258, 4306},
    {4259, 4307},   {4260, 4308},   {4261, 4309},   {4262, 4310},   {4263, 4311},   {4264, 4312},
    {4265, 4313},   {4266, 4314},   {4267, 4315},   {4268, 4316},   {4269, 4317},   {4270, 4318},
    {4271, 4319},   {4272, 4320},   {4273, 4321},   {4274, 4322},   {4275, 4323},   {4276, 4324},
    {4277, 4325},   {4278, 4326},   {4279, 4327},   {4280, 4328},   {4281, 4329},   {4282, 4330},
    {4283, 4331},   {4284, 4332},   {4285, 4333},   {4286, 4334},   {4287, 4335},   {4288, 4336},
    {4289, 4337},   {4290, 4338},   {4291, 4339},   {4292, 4340},   {4293, 4341},   {7680, 7681},
    {7682, 7683},   {7684, 7685},   {7686, 7687},   {7688, 7689},   {7690, 7691},   {7692, 7693},
    {7694, 7695},   {7696, 7697},   {7698, 7699},   {7700, 7701},   {7702, 7703},   {7704, 7705},
    {7706, 7707},   {7708, 7709},   {7710, 7711},   {7712, 7713},   {7714, 7715},   {7716, 7717},
    {7718, 7719},   {7720, 7721},   {7722, 7723},   {7724, 7725},   {7726, 7727},   {7728, 7729},
    {7730, 7731},   {7732, 7733},   {7734, 7735},   {7736, 7737},   {7738, 7739},   {7740, 7741},
    {7742, 7743},   {7744, 7745},   {7746, 7747},   {7748, 7749},   {7750, 7751},   {7752, 7753},
    {7754, 7755},   {7756, 7757},   {7758, 7759},   {7760, 7761},   {7762, 7763},   {7764, 7765},
    {7766, 7767},   {7768, 7769},   {7770, 7771},   {7772, 7773},   {7774, 7775},   {7776, 7777},
    {7778, 7779},   {7780, 7781},   {7782, 7783},   {7784, 7785},   {7786, 7787},   {7788, 7789},
    {7790, 7791},   {7792, 7793},   {7794, 7795},   {7796, 7797},   {7798, 7799},   {7800, 7801},
    {7802, 7803},   {7804, 7805},   {7806, 7807},   {7808, 7809},   {7810, 7811},   {7812, 7813},
    {7814, 7815},   {7816, 7817},   {7818, 7819},   {7820, 7821},   {7822, 7823},   {7824, 7825},
    {7826, 7827},   {7828, 7829},   {7840, 7841},   {7842, 7843},   {7844, 7845},   {7846, 7847},
    {7848, 7849},   {7850, 7851},   {7852, 7853},   {7854, 7855},   {7856, 7857},   {7858, 7859},
    {7860, 7861},   {7862, 7863},   {7864, 7865},   {7866, 7867},   {7868, 7869},   {7870, 7871},
    {7872, 7873},   {7874, 7875},   {7876, 7877},   {7878, 7879},   {7880, 7881},   {7882, 7883},
    {7884, 7885},   {7886, 7887},   {7888, 7889},   {7890, 7891},   {7892, 7893},   {7894, 7895},
    {7896, 7897},   {7898, 7899},   {7900, 7901},   {7902, 7903},   {7904, 7905},   {7906, 7907},
    {7908, 7909},   {7910, 7911},   {7912, 7913},   {7914, 7915},   {7916, 7917},   {7918, 7919},
    {7920, 7921},   {7922, 7923},   {7924, 7925},   {7926, 7927},   {7928, 7929},   {7944, 7936},
    {7945, 7937},   {7946, 7938},   {7947, 7939},   {7948, 7940},   {7949, 7941},   {7950, 7942},
    {7951, 7943},   {7960, 7952},   {7961, 7953},   {7962, 7954},   {7963, 7955},   {7964, 7956},
    {7965, 7957},   {7976, 7968},   {7977, 7969},   {7978, 7970},   {7979, 7971},   {7980, 7972},
    {7981, 7973},   {7982, 7974},   {7983, 7975},   {7992, 7984},   {7993, 7985},   {7994, 7986},
    {7995, 7987},   {7996, 7988},   {7997, 7989},   {7998, 7990},   {7999, 7991},   {8008, 8000},
    {8009, 8001},   {8010, 8002},   {8011, 8003},   {8012, 8004},   {8013, 8005},   {8025, 8017},
    {8027, 8019},   {8029, 8021},   {8031, 8023},   {8040, 8032},   {8041, 8033},   {8042, 8034},
    {8043, 8035},   {8044, 8036},   {8045, 8037},   {8046, 8038},   {8047, 8039},   {8120, 8112},
    {8121, 8113},   {8122, 8048},   {8123, 8049},   {8136, 8050},   {8137, 8051},   {8138, 8052},
    {8139, 8053},   {8152, 8144},   {8153, 8145},   {8154, 8054},   {8155, 8055},   {8168, 8160},
    {8169, 8161},   {8170, 8058},   {8171, 8059},   {8172, 8165},   {8184, 8056},   {8185, 8057},
    {8186, 8060},   {8187, 8061},   {8544, 8560},   {8545, 8561},   {8546, 8562},   {8547, 8563},
    {8548, 8564},   {8549, 8565},   {8550, 8566},   {8551, 8567},   {8552, 8568},   {8553, 8569},
    {8554, 8570},   {8555, 8571},   {8556, 8572},   {8557, 8573},   {8558, 8574},   {8559, 8575},
    {9398, 9424},   {9399, 9425},   {9400, 9426},   {9401, 9427},   {9402, 9428},   {9403, 9429},
    {9404, 9430},   {9405, 9431},   {9406, 9432},   {9407, 9433},   {9408, 9434},   {9409, 9435},
    {9410, 9436},   {9411, 9437},   {9412, 9438},   {9413, 9439},   {9414, 9440},   {9415, 9441},
    {9416, 9442},   {9417, 9443},   {9418, 9444},   {9419, 9445},   {9420, 9446},   {9421, 9447},
    {9422, 9448},   {9423, 9449},   {65313, 65345}, {65314, 65346}, {65315, 65347}, {65316, 65348},
    {65317, 65349}, {65318, 65350}, {65319, 65351}, {65320, 65352}, {65321, 65353}, {65322, 65354},
    {65323, 65355}, {65324, 65356}, {65325, 65357}, {65326, 65358}, {65327, 65359}, {65328, 65360},
    {65329, 65361}, {65330, 65362}, {65331, 65363}, {65332, 65364}, {65333, 65365}, {65334, 65366},
    {65335, 65367}, {65336, 65368}, {65337, 65369}, {65338, 65370}, {65535, 0}};

int OVR_CDECL OVR_towupper(wchar_t charCode) {
  // Don't use UnicodeUpperBits! It differs from UnicodeToUpperBits.
  if (UnicodeCharIs(UnicodeToUpperBits, charCode)) {
    // To protect from memory overrun in case the character is not found
    // we use one extra fake element in the table {65536, 0}.
    size_t idx = Alg::LowerBoundSliced(
        UnicodeToUpperTable,
        0,
        sizeof(UnicodeToUpperTable) / sizeof(UnicodeToUpperTable[0]) - 1,
        (uint16_t)charCode,
        CmpUnicodeKey);
    return UnicodeToUpperTable[idx].Value;
  }
  return charCode;
}

int OVR_CDECL OVR_towlower(wchar_t charCode) {
  // Don't use UnicodeLowerBits! It differs from UnicodeToLowerBits.
  if (UnicodeCharIs(UnicodeToLowerBits, charCode)) {
    // To protect from memory overrun in case the character is not found
    // we use one extra fake element in the table {65536, 0}.
    size_t idx = Alg::LowerBoundSliced(
        UnicodeToLowerTable,
        0,
        sizeof(UnicodeToLowerTable) / sizeof(UnicodeToLowerTable[0]) - 1,
        (uint16_t)charCode,
        CmpUnicodeKey);
    return UnicodeToLowerTable[idx].Value;
  }
  return charCode;
}

#endif // OVR_NO_WCTYPE

} // namespace OVR
